﻿using UnityEngine;
using System.Collections.Generic;
using System;

namespace GameBasic
{
    /// <summary>
    /// TODO: Multi-thread unsafe
    /// </summary>
    public class TaskRunner : MonoSingleton<TaskRunner>
    {
        List<ITask> schedules;
        List<ITask> tasks;

#if UNITY_EDITOR
        int taskCount;
#endif

        public int Count => tasks.Count + schedules.Count;

        protected override void Awake()
        {
            base.Awake();
            schedules = new List<ITask>();
            tasks = new List<ITask>();
        }

        protected override void OnDestroy()
        {
            base.OnDestroy();
            schedules = null;
            tasks = null;
        }

        public void Update()
        {
#if UNITY_EDITOR
            taskCount = Count;
#endif
            if (!HasTask())
                return;
            // 
            tasks.AddRange(schedules);
            schedules.Clear();

            // execute
            for (int i = 0, length = tasks.Count; i < length; i++)
            {
                var t = tasks[i];
                bool end = false;
                if (t.Status == TaskStatus.Kill)
                {
                    end = true;
                }
                else
                {
                    try
                    {
                        // start
                        if (t.Status == TaskStatus.Ready)
                        {
                            t.Status = TaskStatus.Running;
                            t.OnStart();
                        }
                        // update
                        t.OnUpdate();
                        end = t.Status != TaskStatus.Running;
                        // stop
                        if (end)
                            t.OnStop();
                    }
                    catch (Exception e)
                    {
                        end = true;
                        Debug.LogException(e);
                    }
                }

                if (end)
                    t.Status = TaskStatus.End;
            }

            // clear
            tasks.RemoveAll(t => t.Status != TaskStatus.Running);
        }

        public void Add(ITask task)
        {
            if (!task.IsActive())
            {
                task.Status = TaskStatus.Ready;
                schedules.Add(task);
            }
        }

        public bool HasTask()
        {
            return schedules.Count + tasks.Count > 0;
        }

        public void ClearTask()
        {
            schedules.Clear();
            tasks.Clear();
        }

        public static void SetDefault(TaskRunner runner)
        {
            Instance = runner;
        }

        public static void AddToDefault(ITask task)
        {
            Instance?.Add(task);
        }
    }
}